/**
 * Copyright (c) 2022 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "unit_ecma_test.h"
#include "optimizer/ir/datatype.h"
#include "optimizer/ir/graph_cloner.h"
#include "optimizer/optimizations/cleanup.h"
#include "optimizer/optimizations/lowering.h"

namespace ark::compiler {
class LoweringEcmaTest : public AsmTest {
public:
    LoweringEcmaTest() = default;
};

// NOLINTBEGIN(readability-magic-numbers)
TEST_F(LoweringEcmaTest, CastValueToAnyTypeWithConst)
{
    auto graph = CreateGraphDynWithDefaultRuntime();
    GRAPH(graph)
    {
        CONSTANT(0, 0);

        BASIC_BLOCK(2, -1)
        {
            INST(4, Opcode::SaveState).NoVregs();
            INST(1, Opcode::CastValueToAnyType).any().AnyType(AnyBaseType::ECMASCRIPT_BOOLEAN_TYPE).Inputs(0);
            INST(2, Opcode::Intrinsic).any().Inputs({{DataType::ANY, 1}, {DataType::NO_TYPE, 4}});
            INST(3, Opcode::Return).any().Inputs(2);
        }
    }
    auto graphOpt = CreateGraphDynWithDefaultRuntime();
    GRAPH(graphOpt)
    {
        CONSTANT(5, 0x6).any();

        BASIC_BLOCK(2, -1)
        {
            INST(4, Opcode::SaveState).NoVregs();
            INST(2, Opcode::Intrinsic).any().Inputs({{DataType::ANY, 5}, {DataType::NO_TYPE, 4}});
            INST(3, Opcode::Return).any().Inputs(2);
        }
    }

    ASSERT_TRUE(graph->RunPass<Lowering>());
    ASSERT_TRUE(graph->RunPass<Cleanup>());
    GraphChecker(graph).Check();

    EXPECT_TRUE(GraphComparator().Compare(graph, graphOpt));
}

TEST_F(LoweringEcmaTest, CastValueToAnyTypeWithSaveState)
{
    auto graph = CreateGraphDynWithDefaultRuntime();
    GRAPH(graph)
    {
        PARAMETER(0, 0).any();
        CONSTANT(1, 1.1);

        BASIC_BLOCK(2, -1)
        {
            INST(2, Opcode::CastAnyTypeValue).f64().AnyType(AnyBaseType::ECMASCRIPT_DOUBLE_TYPE).Inputs(0);
            INST(3, Opcode::Add).f64().Inputs(2, 1);
            INST(4, Opcode::CastValueToAnyType).any().AnyType(AnyBaseType::ECMASCRIPT_DOUBLE_TYPE).Inputs(3);
            INST(5, Opcode::SaveState).Inputs(4).SrcVregs({0});
            INST(6, Opcode::Intrinsic).any().Inputs({{DataType::NO_TYPE, 5}});
            INST(7, Opcode::Return).any().Inputs(6);
        }
    }
    auto graphOpt = CreateGraphDynWithDefaultRuntime();
    GRAPH(graphOpt)
    {
        PARAMETER(0, 0).any();
        CONSTANT(1, 1.1);

        BASIC_BLOCK(2, -1)
        {
            INST(2, Opcode::CastAnyTypeValue).f64().AnyType(AnyBaseType::ECMASCRIPT_DOUBLE_TYPE).Inputs(0);
            INST(3, Opcode::Add).f64().Inputs(2, 1);
            INST(5, Opcode::SaveState).Inputs(3).SrcVregs({0});
            INST(6, Opcode::Intrinsic).any().Inputs({{DataType::NO_TYPE, 5}});
            INST(7, Opcode::Return).any().Inputs(6);
        }
    }

    ASSERT_TRUE(graph->RunPass<Lowering>());
    ASSERT_TRUE(graph->RunPass<Cleanup>());
    GraphChecker(graph).Check();

    EXPECT_TRUE(GraphComparator().Compare(graph, graphOpt));
}
// NOLINTEND(readability-magic-numbers)

}  // namespace ark::compiler
